#pragma once

#include <iostream>
#include <pthread.h>
#include <vector>
#include <queue>
#include <semaphore.h>
#include "Log.hpp"
#include <functional>
#include <unistd.h>
#include "mythread.hpp"

int g_thread_num = 5;

using func_t = std::function<void()>;

void test(/*const std::string &name*/)
{
    while (true)
    {
        // std::cout << name << " is running! >> test" << std::endl;
        std::cout << "Thread is running!" << std::endl;
        sleep(1);
    }
}

template <class T>
class ThreadPool
{
private:
    int _thread_num;
    std::vector<ThreadMoudle::Thread> _threads;
    std::queue<T> _task;
    bool _is_running = false;
    int _sleep_thread;

    pthread_cond_t _cond;
    pthread_mutex_t _mtx;

private:
    void Lock()
    {
        pthread_mutex_lock(&_mtx);
    }
    void Unlock()
    {
        pthread_mutex_unlock(&_mtx);
    }
    void wakeUp()
    {
        pthread_cond_signal(&_cond);
    }
    bool isEmpty()
    {
        return _task.empty();
    }
    void Sleep()
    {
        pthread_cond_wait(&_cond, &_mtx);
    }
    void handleTask(const std::string& name)
    {
        while (true)
        {
            Lock();
            while (isEmpty() && _is_running)
            {
                _sleep_thread++;
                Sleep();
                _sleep_thread--;
            }
            // 任务队列空，线程池想退出
            if (isEmpty() && !_is_running)
            {
                std::cout << "thread quit" << std::endl;
                Unlock();
                break;
            }
            // 有任务
            T t = _task.front();
            _task.pop();
            Unlock();

            t();
        }
    }
    void Init()
    {
        ThreadMoudle::func_t func = std::bind(&ThreadPool::handleTask, this, std::placeholders::_1);
        for (int i = 0; i < _thread_num; i++)
        {
            std::string name = "thread -" + std::to_string(i + 1) + " 线程创建";
            _threads.emplace_back(name, func /*TODO*/);
        }
    }
    void Start()
    {
        _is_running = true;
        for (auto &thread : _threads)
        {
            thread.Start();
        }
    }
    ThreadPool(int thread_num = g_thread_num)
        : _thread_num(thread_num), _sleep_thread(0)
    {
        pthread_mutex_init(&_mtx, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }
    
    static ThreadPool<T>* _tp;
    static pthread_mutex_t _sig_mutex;

public:
    ThreadPool(const ThreadPool<T> &) = delete;
    ThreadPool<T> &operator=(const ThreadPool<T> &) = delete;

    // 防止多个线程同时创建，需要进行加锁
    static ThreadPool<T>* getInstance()
    {
        pthread_mutex_lock(&_sig_mutex);
        if (_tp == nullptr)
        {
            _tp = new ThreadPool<T>();
            _tp->Init();
            _tp->Start();
        }
        pthread_mutex_unlock(&_sig_mutex);
        return _tp;
    }
    void Equeue(const T &in)
    {
        Lock();
        _task.push(in);
        Unlock();
        if (_sleep_thread > 0)
        {
            wakeUp();
        }
    }
    void Stop()
    {
        _is_running = false;
        for (auto& thread : _threads)
        {
            thread.Stop();
        }
    }
    ~ThreadPool()
    {
        pthread_cond_destroy(&_cond);
        pthread_mutex_destroy(&_mtx);
    }
};

template<class T>
ThreadPool<T> *ThreadPool<T>::_tp = nullptr;
template <class T>
pthread_mutex_t ThreadPool<T>::_sig_mutex = PTHREAD_MUTEX_INITIALIZER;